/**
 * Initial (GUI)
 * -------------------------------------
 * 
 * - This class represents the vision of the program.
 * - Its extend of JFrame and use Swing 
 * 
 * @author Caio Thomas
 * @version 25-10-2013  
 */
package view;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextPane;
import javax.swing.ListSelectionModel;
import javax.swing.border.EtchedBorder;
import javax.swing.table.DefaultTableModel;

import model.constraints.AbstractConstraint;
import model.constraints.synthesized.attributes.SyntAttributesAbstract;
import model.validator.ObserverSaxParser;
import model.validator.ValidateSaxParse;

import org.xml.sax.SAXException;

public class Initial extends JFrame implements ActionListener {

	private static final long serialVersionUID = 1L;
	
	//menu
	public JMenu file = new JMenu("File");		
	public JMenuItem openXML = new JMenuItem("Open XML...");    
	public JMenuItem exit = new JMenuItem("Exit");		
	public JMenu help = new JMenu("Help");
	public JMenuItem menuAbout = new JMenuItem("About");
	public JMenuBar menubar = new JMenuBar();
	public JLabel statusbar = new JLabel("Open file XML to validate....");
	
    //left sidebar menu
	public List<JButton>  buttons = new ArrayList<JButton>();      
	public JButton buttonValidate = new JButton("Validation");        
	public JButton buttonDialog = new JButton("Enter XML-XDF");
	public JButton openF = new JButton("Open XML File");
	public JButton updtF = new JButton("Update List");
	public JButton incvF = new JButton("Update Validation");
	
	//area text
	public JTextPane automataText = new JTextPane();
	public JTextArea xmlTree = new JTextArea(10, 15);	
	public JTextArea xmlText = new JTextArea(10, 15);
	
	public JScrollPane xmlTreeScroll;
	public JScrollPane xmlTextScroll;

	public ValidateSaxParse validate = new ValidateSaxParse();

	//file
	public File f = null;
	public JFileChooser fileChooser = new JFileChooser();
	private String filename = new String();

	//dialog
	private DialogForm dialogXDF = null;
	public static Initial initial = null;
	
	//table
	public final JTable table;
    public DefaultTableModel model = new DefaultTableModel(); 
    
    //table -> popup menu
    private JPopupMenu popupMenu = new JPopupMenu();
    private JMenuItem editItem = new JMenuItem("Edit");
    private JMenuItem viewItem = new JMenuItem("Result");
    private JMenuItem deleteItem = new JMenuItem("Delete");
    
	public Initial(){
		super("XML Constraint Validation");
		initial = this;
		
		automataText.setEditable(false);
		xmlTree.setEditable(false);
		xmlText.setEditable(false);
		
		//menu actions linster
        exit.addActionListener(this);
        openXML.addActionListener(this);
        help.addActionListener(this);
        menuAbout.addActionListener(this);
        
        file.add(openXML);
        file.add(exit);
        help.add(menuAbout);
        menubar.add(file);        
        menubar.add(help);                  
        
        JPanel painelButton = new JPanel();
        painelButton.setLayout(new BoxLayout(painelButton, BoxLayout.Y_AXIS));        
          
    	buttons.add(openF);
		buttons.add(buttonDialog);
		buttons.add(buttonValidate);
		buttons.add(updtF);
		buttons.add(incvF);

        for (JButton button : buttons){
        	button.addActionListener(this);
            button.setPreferredSize(new Dimension(150,30));
            button.setMaximumSize(new Dimension(150,30));
            button.setEnabled(false);            
            painelButton.add(button);  
            painelButton.add(Box.createRigidArea(new Dimension(0, 3)));            
        }     
        
        openF.setEnabled(true);            
        
        //panel automata
    	JPanel panelAutomata = new JPanel();     
    	panelAutomata.setLayout(new BorderLayout());
        panelAutomata.setBorder(BorderFactory.createTitledBorder("Automata")); 
        automataText.setContentType("text/html");
        automataText.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        panelAutomata.add(new JScrollPane(automataText));
        
        //tree xml
    	JPanel panelXMLTree = new JPanel();  
    	panelXMLTree.setLayout(new BorderLayout());    	
    	xmlTreeScroll = new JScrollPane(xmlTree);
    	panelXMLTree.add(xmlTreeScroll);
    	
    	//xml text
    	JPanel panelXMLText = new JPanel();  
    	panelXMLText.setLayout(new BorderLayout());   
    	xmlTextScroll = new JScrollPane(xmlText);    	
    	panelXMLText.add(xmlTextScroll);
    	
    	JPanel panelXml = new JPanel();     
    	panelXml.setLayout(new BorderLayout());
    	
    	//insert tabs of text and tree
    	JTabbedPane tabbedPane = new JTabbedPane();
    	tabbedPane.addTab("XML Document",panelXMLTree);
    	tabbedPane.addTab("File",panelXMLText);
        
        JPanel panelTop = new JPanel();                
        JPanel panelEst = new JPanel();        
        panelEst.setLayout(new GridLayout(1,2));
        panelEst.add(tabbedPane);
        panelEst.add(panelAutomata);
        
        panelTop.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        panelTop.setLayout(new BorderLayout());
        panelTop.add(painelButton,BorderLayout.WEST);
        panelTop.add(panelEst,BorderLayout.CENTER);

        JPanel panelSouth = new JPanel();
        JPanel panelTable = new JPanel();        
        
        panelSouth.setLayout(new BorderLayout());
        panelTable.setLayout(new GridLayout(1, 1, 1, 1));  
        panelTable.setBorder(BorderFactory.createTitledBorder("Results")); 
        
        //table
        table = new JTable(model){   
			private static final long serialVersionUID = 1L;

			public boolean isCellEditable(int row, int col) {  
            	return false;
            }           
        };

        //insert columns of jtable
        String[] columnNames = {"Name", "Result", "Constraint Inters"};
        
        for(String name: columnNames)
        	model.addColumn(name);                
         
        table.getColumnModel().getColumn(0).setPreferredWidth(40);
        table.getColumnModel().getColumn(1).setPreferredWidth(50);
        table.getColumnModel().getColumn(2).setPreferredWidth(550);
                             
        popupMenu.add(viewItem);
        popupMenu.add(editItem);
        popupMenu.add(deleteItem);
        
        viewItem.addActionListener(this);
        editItem.addActionListener(this);
        deleteItem.addActionListener(this);
        
        table.setComponentPopupMenu(popupMenu);
        
        table.addMouseListener( new MouseAdapter(){
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()){
                    JTable source = (JTable)e.getSource();
                    int row = source.rowAtPoint(e.getPoint());
                    int column = source.columnAtPoint(e.getPoint());

                    if (!source.isRowSelected(row))
                        source.changeSelection(row, column, false, false);                                      	
						popupMenu.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        });                   
        
        table.setFillsViewportHeight(true);     
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        table.setPreferredScrollableViewportSize(new Dimension(0,140)); 
        panelTable.add(new JScrollPane(table));         
        panelSouth.add(panelTable);
        
        statusbar.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
        panelSouth.add(statusbar, BorderLayout.SOUTH);
        
        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(panelTop);
        getContentPane().add(panelSouth, BorderLayout.SOUTH);

        //this.pack();        
        this.setJMenuBar(menubar);
		this.setSize(800, 550);
		this.setVisible(true);	
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);        
	}
	
	private String selectFile() {		
		String name = new String();
		
		fileChooser.setDialogTitle("Select a xml file");
		fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
		filterFile(fileChooser);
		String s = System.getProperty("user.dir");
		File f1 = new File (s);
		fileChooser.setCurrentDirectory(f1);
		
		//Save the last path selected to oppen the chooser in there
		if (f != null ) {
			String path = fileChooser.getSelectedFile().getAbsolutePath();
			String lastPath;
			
			if(!LookAndFeel.isUnix())
				lastPath = path.substring(0, path.lastIndexOf("\\"));
			else
				lastPath = path.substring(0, path.lastIndexOf("/"));
			
			f = new File(lastPath);
			fileChooser.setCurrentDirectory(f);
			path = "" + f;
		}
		
		int result = fileChooser.showDialog(fileChooser.getParent(), null) ;

		if (result == JFileChooser.CANCEL_OPTION)
			return "error";
		else {
			name = fileChooser.getSelectedFile().getAbsolutePath() ;
			f = new File (name);
			return name;
		}
	}
	
	/**
	 * Lets just xml files are selected by the JFileChooser
	 */
	public void filterFile(JFileChooser j){			
		j.setFileFilter(new javax.swing.filechooser.FileFilter() {
			
			public boolean accept (File f){
				return f.getName().toLowerCase().endsWith(".xml") || f.isDirectory();
			}
			
			//Text show to user
			public String getDescription(){
				return "Only files xml (.xml)";
			}
			
		});
	}			
	
	@Override
	public void actionPerformed(ActionEvent e) {
		Object origem = e.getSource();
		
		if(origem == exit)
        	System.exit(0);
		else if (origem == viewItem) { // view item command from jtable
			if (table.getSelectedRow() >= 0)
				new DialogResults(table.getSelectedRow(), Initial.initial).setVisible(true);
		} else if (origem == editItem) { // edit item command from jtable
			if (table.getSelectedRow() >= 0){
				AbstractConstraint ab = (AbstractConstraint) validate.getConstraints().get(table.getSelectedRow()).getConstraint();
				singleDialogXDF().setTextDialog(ab, table.getSelectedRow());
			}				
		} else if (origem == deleteItem) { // delete item from jtable

			if (table.getSelectedRow() >= 0){			
			
				int result = JOptionPane.showConfirmDialog(null,"Do you want delete constraint? ","Delete",JOptionPane.YES_NO_OPTION);   
				int p = table.getSelectedRow();
				
				if(result == JOptionPane.YES_OPTION) {          			
					((DefaultTableModel)table.getModel()).removeRow(p);
					validate.getConstraints().remove(p);  
				}
			}
		} else if(origem == buttonDialog) // show the dialog
			singleDialogXDF().setVisible(true);
        else if(origem == buttonValidate){ // command validate tree XML
        	
        	try{			
				validate.parse(filename); // validate				
				
				makeTable(); // create table
				displayAutomata(); // update automata
				
				statusbar.setText("File validated!"); // insert status in status bar							
			} catch (Exception ex){
				ex.printStackTrace();
                JOptionPane.showMessageDialog(this,"Error Validation:" + ex.getMessage(), "Attention", JOptionPane.ERROR_MESSAGE);                                                                        				
				System.err.println("Error KTree:" + ex.getMessage());
			}		
		}  		
		else if(origem == openF || origem == openXML) {			
			int size = 999000000;
			filename = selectFile();
			
			if(!filename.equals("error")) {
				
				File f = new File (filename);
				
				if (f.length() < size){ // Tests the file size if it is larger than 50MB will not be displayed											
				
					Tree t = new Tree();
					long timeInit = System.currentTimeMillis(); 
						
					try {
						xmlTreeScroll.setViewportView(t.createTree(filename));
						xmlText.setText(t.getDocument());
					} catch (SAXException e1) {
				        JOptionPane.showMessageDialog(null, "Error SaxException: tags of XML!", "Erro", JOptionPane.ERROR_MESSAGE);  
						//e1.printStackTrace();
					} catch (IOException e1) {
						 JOptionPane.showMessageDialog(null, "Error IOException: checks your file XML!", "Erro", JOptionPane.ERROR_MESSAGE);
						//e1.printStackTrace();
					}						

				    long timeEnd = System.currentTimeMillis();

					statusbar.setText("Time reading XML file: "+ ((timeEnd - timeInit)/60000000) + " minutes." );
					repaint();
					
				} else {
					JOptionPane.showMessageDialog(null, "The file  " + filename + "\n is larger than " + size+" bytes, will not be displayed.");
					xmlTree.setText("The file: \n"+ filename+ "\n" + " is very big to be displayed.");
					xmlText.setText("The file: \n"+ filename+ "\n" + " is very big to be displayed.");
					statusbar.setText("The file: \n"+ filename+ "\n" + " is very big to be displayed.");
				}
			
				buttonDialog.setEnabled(true);		
			}
		} else if (origem == menuAbout)
	    	JOptionPane.showMessageDialog(this, "Faculdade de Computação - Universidade Federal de Uberlândia\n2014", "About", JOptionPane.INFORMATION_MESSAGE);
		
	}
	
	/**
	 * This function will insert values of validation constraint
	 * @rerturn void
	 */
	@SuppressWarnings("unchecked")
	public void  makeTable(){		   
		Stack<Vector<SyntAttributesAbstract>> synt = new Stack<Vector<SyntAttributesAbstract>>();
		model.getDataVector().removeAllElements();
		for(ObserverSaxParser restricao: validate.getConstraints()){
			synt = (Stack<Vector<SyntAttributesAbstract>>) restricao.getStackSynt();
			AbstractConstraint ab = (AbstractConstraint) restricao.getConstraint();
			model.addRow(new Object[]{ab.getNameConstraint(), synt.peek().get(0).getC().toString(), restricao.getResult()});			
		}	                
	}
	
	/**
	 * Singleton patterns of dialog, create only one instance of dialog 
	 * @return the view Dialog
	 */
	public DialogForm singleDialogXDF() {
		if(dialogXDF == null)
			dialogXDF = new DialogForm(this);
		else
			dialogXDF.clean();
		return dialogXDF;
	}
	
	/**
	 * Used when it was removed or updated the constraint XML
	 * @return void
	 */
	public void displayAutomata() {
		String strAutomata = new String();
		strAutomata = "<span style=\"font-family: arial, verdana, sans-serif;font-size:9px;\">";
		
		for(ObserverSaxParser restricao: initial.validate.getConstraints())
			strAutomata += restricao.getConstraint().toString() + "<br><br>";
		
		strAutomata += "</font> </span>";
		automataText.setText(strAutomata);  		
	}
	
	public static void main(String[] args){
		LookAndFeel.initLookAndFeel();
		new Initial();		
	}		
}